﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Platform.LanguageProcessing.Expressions;

namespace Platform.LanguageProcessing.Cultures
{

	/// <summary>
	/// Gramática da língua inglesa
	/// </summary>
	public sealed class EnglishGrammar : Grammar
	{

		public EnglishGrammar()
			: base( CultureInfo.GetCultureInfo( "en-US" ) )
		{
			base.AddWordParser( "i", new PronounWordParser( PersonVerb.FirstSingle, SubjectGender.Neutral ) );
			base.AddWordParser( "he", new PronounWordParser (PersonVerb.ThirdSingle, SubjectGender.Male));
			base.AddWordParser( "she", new PronounWordParser(PersonVerb.ThirdSingle, SubjectGender.Female));
			base.AddWordParser( "it", new PronounWordParser(PersonVerb.ThirdSingle));

			base.AddWordParser( "we", new PronounWordParser( PersonVerb.FirstPlural ) );
			base.AddWordParser( "they", new PronounWordParser( PersonVerb.ThirdPlural ) );
			base.AddWordParser( "you", new YouPronounWordParser() );

			base.AddWordParser( new[] { "a", "an" }, new PrepositionWordParser( Cardinality.AnyButOne ) );
			base.AddWordParser( new[] { "the", "of" }, new PrepositionWordParser( Cardinality.JustOne ) );

			base.AddWordParser( new[] { "happen", "fish" }, new RegularVerbWordParser() );
		}


		public override Parser CreateParser()
		{
			return new EnglishParser( this );
		}

		/// <summary>
		/// 
		/// </summary>
		// TODO : Não vai mais existir "EnglishParser", transformar em EnglishSyntaxAnalyser
		public sealed class EnglishParser : Parser
		{

			internal EnglishParser( EnglishGrammar grammar )
				: base( new SyntaxAnalyzer(), grammar )
			{ }

			protected override GrammarExpression ParseNoun( string word, ParserContext context )
			{
				return new NounExpression( word );
			}

			protected override void ParsePeriod( ParserContext context )
			{
				IEnumerable<GrammarExpression> predicate = context.PopUntil( x => x is VerbExpression ).ToList();

				Debug.Assert( !context.Expressions.IsEmpty, "Essa frase não tem verbo !!!" );
				VerbExpression verb = ( VerbExpression )context.Expressions.Pop();

				context.PopUntil( x => x is SentenceExpression );

				List<GrammarExpression> subject = new List<GrammarExpression>( context.PopUntil( x => x is SentenceExpression ) );

				if ( subject.Count == 0 )
				{
					// TODO : Sujeito oculto, deve ser inferido através do verbo
				}

				context.Expressions.Push( new SentenceExpression( subject, verb, predicate ) );
			}
		}


		internal sealed class NounWordParser : IWordParser
		{

			#region IWordParser Members

			public GrammarExpression Parse( string word, ParserContext context )
			{
				return new NounExpression( word );
			}

			#endregion
		}

		internal sealed class PronounWordParser : IWordParser
		{
			public PronounWordParser( PersonVerb person )
				: this( person, SubjectGender.Neutral )
			{ }

			public PronounWordParser( PersonVerb person, SubjectGender gender )
			{
				this.Person = person;
				this.Gender = gender;
			}

			public SubjectGender Gender
			{ get; private set; }

			public PersonVerb Person
			{ get; private set; }

			#region IWordParser Members

			public GrammarExpression Parse( string word, ParserContext context )
			{
				// TODO : Deve fazer as verificações do que já foi "parseado"

				// Algumas verificações:
				// 1-Concorda com genero e número
				return new PronounExpression( word, this.Gender, this.Person );
			}

			#endregion
		}

		internal sealed class YouPronounWordParser : IWordParser
		{

			#region IWordParser Members

			public GrammarExpression Parse( string word, ParserContext context )
			{
				// TODO : Adicionar lógica necessária para definir se é plural ou singular
				return new PronounExpression( word, SubjectGender.Neutral, PersonVerb.SecondPlural );
			}

			#endregion
		}


		internal sealed class PrepositionWordParser : IWordParser
		{
			public PrepositionWordParser( Cardinality cardinality )
			{
				this.Cardinality = cardinality;
			}

			public Cardinality Cardinality
			{ get; private set; }

			#region IWordParser Members

			public GrammarExpression Parse( string word, ParserContext context )
			{
				return new PrepositionExpression( word, this.Cardinality );
			}

			#endregion
		}

		internal sealed class RegularVerbWordParser : IWordParser
		{
			#region IWordParser Members

			public GrammarExpression Parse( string word, ParserContext context )
			{
				int lastCharIndex = word.Length - 1;
				char lastChar = word[ lastCharIndex ];
				Verb verb = null;

				switch ( lastChar )
				{
					case 'd':
						if ( word[ lastCharIndex - 1 ] == 'e' && word[ lastCharIndex - 2 ].IsConsonant() )
						{
							verb = new Verb( word, VerbTense.Past, PersonVerb.Unknow );
						}
						break;

					case 's':
						if ( word[ lastCharIndex - 1 ] == 'o' && word[ lastCharIndex - 2 ].IsVowel() )
						{
							verb = new Verb( word, VerbTense.Present, PersonVerb.Unknow );
						}
						else if ( word[ lastCharIndex - 1 ].IsVowel() )
						{
							verb = new Verb( word, VerbTense.Present, PersonVerb.Unknow );
						}
						break;
				}

				if ( verb != null )
				{
					return new VerbExpression( verb );
				}
				else
				{
					return null;
				}
			}

			#endregion
		}
	}




	internal static class GrammarExtensionMethods
	{

		public static bool IsVowel( this char c )
		{
			if ( char.IsLetter( c ) )
			{
				switch ( c )
				{
					case 'a':
					case 'e':
					case 'i':
					case 'o': 
					case 'u':
					case 'A':
					case 'E':
					case 'I':
					case 'O': 
					case 'U':
						return true;
				}
			}

			return false;
		}

		public static bool IsConsonant( this char c )
		{
			
			if ( char.IsLetter( c ) )
			{
				return !c.IsVowel();
			}
			else
			{
				return false;
			}
		}
	}
}
